package notify

import (
	"context"
	"encoding/json"
	"fmt"
	"net/url"
	"time"

	"open/internal/model"
	"open/internal/types"
	"open/pkg/log"
)

// Detail 授权详情
type Detail struct {
	AppID           string `json:"app_id"`
	AuthAppID       string `json:"auth_app_id"`
	AuthTime        int64  `json:"auth_time"`
	AppAuthCode     string `json:"app_auth_code"`
	AppAuthToken    string `json:"app_auth_token"`
	ExpiresIn       int64  `json:"expires_in"`
	AppRefreshToken string `json:"app_refresh_token"`
	ReExpiresIn     int64  `json:"re_expires_in"`
	UserID          string `json:"user_id"`
}

// AuthNotify 授权通知内容
type AuthNotify struct {
	Detail Detail `json:"detail"`
}

// AuthCanceled 取消授权通知
type AuthCanceled struct {
	AppID        string `json:"app_id"`
	AuthAppID    string `json:"auth_app_id"`
	AppAuthToken string `json:"app_auth_token"`
	UserID       string `json:"user_id"`
}

// NotifyAlipay 支付宝通知
func (s *Service) NotifyAlipay(ctx context.Context, form url.Values) (string, error) {
	sign := form.Get("sign")
	service := form.Get("service")
	if service == "alipay.service.check" {
		return s.dao.AlipaySuccessWithSign(), nil
	}
	log.FromContext(ctx).Info(form.Encode())
	if err := s.dao.VerifyAlipaySign(form, sign); err != nil {
		return "", fmt.Errorf("支付宝异步验签名失败")
	}
	notifyType := form.Get("notify_type")
	if notifyType != "" {
		switch notifyType {
		case "open_app_auth_notify":
			bizContent := form.Get("biz_content")
			if bizContent != "" {
				event := AuthNotify{}
				if err := json.Unmarshal([]byte(bizContent), &event); err != nil {
					return "", err
				}
				authTime := time.Unix(event.Detail.AuthTime, 0)
				if err := s.dao.CreateAlipayOpenSubApp(ctx, &model.AlipayOpenSubApp{
					AppID:           event.Detail.AuthAppID,
					OpenAppID:       event.Detail.AppID,
					AuthTime:        authTime,
					AppAuthCode:     event.Detail.AppAuthCode,
					AppAuthToken:    event.Detail.AppAuthToken,
					AppRefreshToken: event.Detail.AppRefreshToken,
					ReExpiresAt:     authTime.Add(time.Duration(event.Detail.ReExpiresIn) * time.Second),
					NotifyID:        form.Get("notify_id"),
					UserID:          event.Detail.UserID,
					Status:          types.AlipayAuthorized,
				}); err != nil {
					return "", err
				}
			}

			//case "servicemarket_order_notify":

		}
	}
	msgMethod := form.Get("msg_method")
	if msgMethod != "" {
		switch msgMethod {
		case "alipay.open.auth.appauth.cancelled":
			bizContent := form.Get("biz_content")
			if bizContent != "" {
				event := AuthCanceled{}
				if err := json.Unmarshal([]byte(bizContent), &event); err != nil {
					return "", err
				}
				err := s.dao.Transaction(ctx, func(ctx context.Context) error {
					subApp, err := s.dao.LockAlipaySubApp(ctx, event.AuthAppID)
					if err != nil {
						return err
					}
					subApp.Status = types.AlipayUnauthorized
					if err := s.dao.SaveAlipaySubApp(ctx, subApp); err != nil {
						return err
					}
					return nil
				})
				if err != nil {
					return "", err
				}
			}

		}
	}
	return "success", nil
}
